bitkeeper revision 1.1041.1.1 (40e2c78cfPsfEf6gMo2dzBk-JDH8iw)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Wed, 30 Jun 2004 14:00:44 +0000 (14:00 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Wed, 30 Jun 2004 14:00:44 +0000 (14:00 +0000)
Fix refcnting on Xen heap pages mapped by guests.

xen/common/dom0_ops.c
xen/common/domain.c
xen/common/keyhandler.c
xen/common/memory.c
xen/include/xen/mm.h
xen/include/xen/sched.h

index 83cc82f6edd010116d7cfe88c5fe648e17e02cf5..96d7197b3e92ebf0c1d1a224ee19079af65b5923 100644 (file)
@@ -247,7 +247,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
         {
             ret = 0;
 
-            spin_lock(&d->page_list_lock);
+            spin_lock(&d->page_alloc_lock);
             list_ent = d->page_list.next;
             for ( i = 0; (i < max_pfns) && (list_ent != &d->page_list); i++ )
             {
@@ -261,7 +261,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
                 buffer++;
                 list_ent = frame_table[pfn].list.next;
             }
-            spin_unlock(&d->page_list_lock);
+            spin_unlock(&d->page_alloc_lock);
 
             op->u.getmemlist.num_pfns = i;
             copy_to_user(u_dom0_op, op, sizeof(*op));
index f85b7443042c5f5d01ba4e2bcf233138069720c7..5375a5de1892dfd528c6a81fa440fc50e89da729 100644 (file)
@@ -80,7 +80,7 @@ struct domain *do_createdomain(domid_t dom_id, unsigned int cpu)
 
         d->addr_limit = USER_DS;
         
-        spin_lock_init(&d->page_list_lock);
+        spin_lock_init(&d->page_alloc_lock);
         INIT_LIST_HEAD(&d->page_list);
         d->max_pages = d->tot_pages = 0;
 
@@ -260,19 +260,19 @@ struct pfn_info *alloc_domain_page(struct domain *d)
     if ( d != NULL )
     {
         wmb(); /* Domain pointer must be visible before updating refcnt. */
-        spin_lock(&d->page_list_lock);
+        spin_lock(&d->page_alloc_lock);
         if ( unlikely(d->tot_pages >= d->max_pages) )
         {
             DPRINTK("Over-allocation for domain %u: %u >= %u\n",
                     d->domain, d->tot_pages, d->max_pages);
-            spin_unlock(&d->page_list_lock);
+            spin_unlock(&d->page_alloc_lock);
             goto free_and_exit;
         }
         list_add_tail(&page->list, &d->page_list);
         page->count_and_flags = PGC_allocated | 1;
         if ( unlikely(d->tot_pages++ == 0) )
             get_domain(d);
-        spin_unlock(&d->page_list_lock);
+        spin_unlock(&d->page_alloc_lock);
     }
 
     return page;
@@ -291,27 +291,33 @@ void free_domain_page(struct pfn_info *page)
     int            drop_dom_ref;
     struct domain *d = page->u.domain;
 
-    /* Deallocation of such pages is handled out of band. */
     if ( unlikely(IS_XEN_HEAP_FRAME(page)) )
-        return;
+    {
+        spin_lock_recursive(&d->page_alloc_lock);
+        drop_dom_ref = (--d->xenheap_pages == 0);
+        spin_unlock_recursive(&d->page_alloc_lock);
+    }
+    else
+    {
+        page->tlbflush_timestamp = tlbflush_clock;
+        page->u.cpu_mask = 1 << d->processor;
+        
+        /* NB. May recursively lock from domain_relinquish_memory(). */
+        spin_lock_recursive(&d->page_alloc_lock);
+        list_del(&page->list);
+        drop_dom_ref = (--d->tot_pages == 0);
+        spin_unlock_recursive(&d->page_alloc_lock);
 
-    page->tlbflush_timestamp = tlbflush_clock;
-    page->u.cpu_mask = 1 << d->processor;
+        page->count_and_flags = 0;
+        
+        spin_lock_irqsave(&free_list_lock, flags);
+        list_add(&page->list, &free_list);
+        free_pfns++;
+        spin_unlock_irqrestore(&free_list_lock, flags);
+    }
 
-    /* NB. May recursively lock from domain_relinquish_memory(). */
-    spin_lock_recursive(&d->page_list_lock);
-    list_del(&page->list);
-    drop_dom_ref = (--d->tot_pages == 0);
-    spin_unlock_recursive(&d->page_list_lock);
     if ( drop_dom_ref )
         put_domain(d);
-
-    page->count_and_flags = 0;
-    
-    spin_lock_irqsave(&free_list_lock, flags);
-    list_add(&page->list, &free_list);
-    free_pfns++;
-    spin_unlock_irqrestore(&free_list_lock, flags);
 }
 
 
@@ -337,8 +343,13 @@ void domain_relinquish_memory(struct domain *d)
         put_page_and_type(&frame_table[pagetable_val(d->mm.pagetable) >>
                                       PAGE_SHIFT]);
 
+    /* Relinquish Xen-heap pages. Currently this can only be 'shared_info'. */
+    page = virt_to_page(d->shared_info);
+    if ( test_and_clear_bit(_PGC_allocated, &page->count_and_flags) )
+        put_page(page);
+
     /* Relinquish all pages on the domain's allocation list. */
-    spin_lock_recursive(&d->page_list_lock); /* may enter free_domain_page() */
+    spin_lock_recursive(&d->page_alloc_lock); /* may enter free_domain_page */
     list_for_each_safe ( ent, tmp, &d->page_list )
     {
         page = list_entry(ent, struct pfn_info, list);
@@ -367,7 +378,7 @@ void domain_relinquish_memory(struct domain *d)
         }
         while ( unlikely(y != x) );
     }
-    spin_unlock_recursive(&d->page_list_lock);
+    spin_unlock_recursive(&d->page_alloc_lock);
 }
 
 
@@ -774,11 +785,11 @@ int construct_dom0(struct domain *p,
     }
 
     /* Construct a frame-allocation list for the initial domain. */
-    for ( pfn = (alloc_start>>PAGE_SHIFT); 
-          pfn < (alloc_end>>PAGE_SHIFT); 
-          pfn++ )
+    for ( mfn = (alloc_start>>PAGE_SHIFT); 
+          mfn < (alloc_end>>PAGE_SHIFT); 
+          mfn++ )
     {
-        page = &frame_table[pfn];
+        page = &frame_table[mfn];
         page->u.domain        = p;
         page->type_and_flags  = 0;
         page->count_and_flags = PGC_allocated | 1;
@@ -890,9 +901,11 @@ int construct_dom0(struct domain *p,
     si->mfn_list     = vphysmap_start;
 
     /* Write the phys->machine and machine->phys table entries. */
-    for ( pfn = 0; pfn < p->tot_pages; pfn++ )
+    for ( mfn = (alloc_start>>PAGE_SHIFT); 
+          mfn < (alloc_end>>PAGE_SHIFT); 
+          mfn++ )
     {
-        mfn = (alloc_start >> PAGE_SHIFT) + pfn;
+        pfn = mfn - (alloc_start>>PAGE_SHIFT);
         ((unsigned long *)vphysmap_start)[pfn] = mfn;
         machine_to_phys_mapping[mfn] = pfn;
     }
index 7365d5cb9073c9d6c555c883bdba776af15a0cc5..aff7ccfd1b62851dd26f0c0ec634df9f10748aeb 100644 (file)
@@ -60,6 +60,8 @@ void do_task_queues(unsigned char key, void *dev_id,
     unsigned long  flags;
     struct domain *d;
     s_time_t       now = NOW();
+    struct list_head *ent;
+    struct pfn_info  *page;
 
     printk("'%c' pressed -> dumping task queues (now=0x%X:%08X)\n", key,
            (u32)(now>>32), (u32)now); 
@@ -68,10 +70,28 @@ void do_task_queues(unsigned char key, void *dev_id,
 
     for_each_domain ( d )
     {
-        printk("Xen: DOM %u, CPU %d [has=%c] refcnt=%d nr_pages=%d\n",
+        printk("Xen: DOM %u, CPU %d [has=%c] refcnt=%d nr_pages=%d "
+               "xenheap_pages=%d\n",
                d->domain, d->processor, 
                test_bit(DF_RUNNING, &d->flags) ? 'T':'F',
-               atomic_read(&d->refcnt), d->tot_pages);
+               atomic_read(&d->refcnt), d->tot_pages, d->xenheap_pages);
+
+        if ( d->tot_pages < 10 )
+        {
+            list_for_each ( ent, &d->page_list )
+            {
+                page = list_entry(ent, struct pfn_info, list);
+                printk("Page %08x: caf=%08x, taf=%08x\n",
+                       page_to_phys(page), page->count_and_flags,
+                       page->type_and_flags);
+            }
+        }
+
+        page = virt_to_page(d->shared_info);
+        printk("Shared_info@%08x: caf=%08x, taf=%08x\n",
+               page_to_phys(page), page->count_and_flags,
+               page->type_and_flags);
+               
         printk("Guest: upcall_pend = %02x, upcall_mask = %02x\n", 
                d->shared_info->vcpu_data[0].evtchn_upcall_pending, 
                d->shared_info->vcpu_data[0].evtchn_upcall_mask);
index 4675a95d2e9969f3329689f3273d9547f5ce9af3..d83d7111dcf3c84efbb68eaf02e839915d3af2e1 100644 (file)
@@ -907,17 +907,18 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
          */
         if ( d < e )
         {
-            spin_lock(&d->page_list_lock);
-            spin_lock(&e->page_list_lock);
+            spin_lock(&d->page_alloc_lock);
+            spin_lock(&e->page_alloc_lock);
         }
         else
         {
-            spin_lock(&e->page_list_lock);
-            spin_lock(&d->page_list_lock);
+            spin_lock(&e->page_alloc_lock);
+            spin_lock(&d->page_alloc_lock);
         }
 
         /* A domain shouldn't have PGC_allocated pages when it is dying. */
-        if ( unlikely(test_bit(DF_DYING, &e->flags)) )
+        if ( unlikely(test_bit(DF_DYING, &e->flags)) ||
+             unlikely(IS_XEN_HEAP_FRAME(page)) )
         {
             okay = 0;
             goto reassign_fail;
@@ -967,8 +968,8 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
         list_add_tail(&page->list, &e->page_list);
 
     reassign_fail:        
-        spin_unlock(&d->page_list_lock);
-        spin_unlock(&e->page_list_lock);
+        spin_unlock(&d->page_alloc_lock);
+        spin_unlock(&e->page_alloc_lock);
         break;
 
     case MMUEXT_RESET_SUBJECTDOM:
index 4688037deb453242630a1c1d87f1f163d29a6026..c9eaae530af0f3d87dcd821a4c57070489caa4b5 100644 (file)
@@ -91,11 +91,15 @@ struct pfn_info
 #define SHARE_PFN_WITH_DOMAIN(_pfn, _dom)                                   \
     do {                                                                    \
         (_pfn)->u.domain = (_dom);                                          \
+        /* The incremented type count is intended to pin to 'writeable'. */ \
+        (_pfn)->type_and_flags  = PGT_writeable_page | PGT_validated | 1;   \
         wmb(); /* install valid domain ptr before updating refcnt. */       \
+        spin_lock(&(_dom)->page_alloc_lock);                                \
         /* _dom holds an allocation reference */                            \
         (_pfn)->count_and_flags = PGC_allocated | 1;                        \
-        /* The incremented type count is intended to pin to 'writeable'. */ \
-        (_pfn)->type_and_flags  = PGT_writeable_page | PGT_validated | 1;   \
+        if ( unlikely((_dom)->xenheap_pages++ == 0) )                       \
+            get_domain(_dom);                                               \
+        spin_unlock(&(_dom)->page_alloc_lock);                              \
     } while ( 0 )
 
 extern struct pfn_info *frame_table;
index fb4ab16ba3e7564a75b0409cac41ddbba1d43401..009ce5f5e399647cbb4b99251fa9afd7b4614b61 100644 (file)
@@ -89,10 +89,11 @@ struct domain
     char     name[MAX_DOMAIN_NAME];
     s_time_t create_time;
 
-    spinlock_t       page_list_lock;
-    struct list_head page_list;
-    unsigned int     tot_pages; /* number of pages currently possesed */
-    unsigned int     max_pages; /* max number of pages that can be possesed */
+    spinlock_t       page_alloc_lock; /* protects all the following fields  */
+    struct list_head page_list;       /* linked list, of size tot_pages     */
+    unsigned int     tot_pages;       /* number of pages currently possesed */
+    unsigned int     max_pages;       /* maximum value for tot_pages        */
+    unsigned int     xenheap_pages;   /* # pages allocated from Xen heap    */
 
     /* Scheduling. */
     struct list_head run_list;